home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Pascal / Snippets / ColorIcosahedron 1.0 / ColorIcosahedron.p < prev    next >
Text File  |  1995-10-26  |  26KB  |  1,064 lines

  1. program Univ_of_Utah (INPUT, OUTPUT);
  2.  
  3. {            Icosahedron display program               }
  4. { (c) Copyright 1986 University of Utah Computer Center, }
  5. {      Written by John B. Halleck (NSS 20620)          }
  6.  
  7. {Ken Long digged it up and made it run again 1994.}
  8. {Modernized by Ingemar R 1995 (grayscales rather than patterns,}
  9. {color palette, delays, GWorlds).}
  10. {}
  11. {The program is *not* completely useable under MetroWerks Pascal, but the most}
  12. {important parts (uses, initialization) are included.}
  13. {}
  14. {Second color version, 26 oct -95: The first had a few flaws that made it work poorly}
  15. {under some systems. This version is a bit more careful in the port setting, which seems}
  16. {to help.}
  17.  
  18.     uses
  19.  {$IFC UNDEFINED THINK_PASCAL}
  20.         MemTypes, QuickDraw, OSUtils, ToolUtils, Windows, Fonts, Menus, TextEdit, {}
  21.         Dialogs, Memory, 
  22. {$ENDC}
  23.         Palettes, OffscreenToysUtils;
  24.  
  25.     const
  26.         kFullHeight = 128;    { How big is our screen image? }
  27.         kHalfHeight = 64;    { Height of half of a screen image }
  28.         kByteHeight = 16;    { kFullHeight covered divide 8}
  29.  
  30.         PI = 3.141592653;  { Pi }
  31.  
  32.         kNumVertices = 12; { Vertices in an Icosahedron }
  33.         kNumFaces = 20; { faces in an Icosahedron    }
  34.         kNumEdges = 30; { edges in an Icosahedron    }
  35.  
  36.         kNumViews = 20; { Rotation in how many steps?}
  37.  
  38.  
  39.     type
  40.         Transform = array[1..3, 1..3] of Real; { Transformation matrices }
  41.  
  42.         Coordinates = array[1..3] of Real; { 3 space coordinates. }
  43.  
  44.         View = packed array[1..kFullHeight, 1..kByteHeight] of 0..255;
  45.          { Storage for the views. }
  46.  
  47.         Apoint = record { Information we keep for each point   }
  48.                 DX, DY: Integer;     { Display Coordinates.  }
  49.                 Where: Coordinates; { Original Coordinates. }
  50.                 NowAt: Coordinates; { Final Coordinates.    }
  51.             end;
  52.  
  53.         AnEdge = record { Information for each edge }
  54.                 Visible: Boolean; { Is the edge visible?        }
  55.                 Start, Finish: Integer; { Which vertices does it connect? }
  56.             end;
  57.  
  58.         Aface = record { Information about each face }
  59.                 Bedges: array[1..3] of integer; { What bounding edges    }
  60.                 BVert: array[1..3] of integer; { What corner vertices   }
  61.                 ONormal: Coordinates;             { Original Surface Normal}
  62.                 Normal: Coordinates;             { Final Surface Normal   }
  63.                 Shows: Boolean;           {Is it visible?          }
  64.             end;
  65.  
  66.     var
  67.  
  68.         index: Integer; { General loop index}
  69.  
  70.    { How does the Icosahedron connect together? }
  71.         Vertices: array[1..kNumVertices] of Apoint;
  72.         edges: array[1..kNumEdges] of AnEdge;
  73.         faces: array[1..kNumFaces] of Aface;
  74.  
  75.         light: Coordinates; {Where is the light source?}
  76.  
  77.         patterns: array[0..64] of Pattern; {Brightness patterns for shading}
  78.         cpatterns: array[0..64] of RGBColor; {Brightness colors for shading}
  79.  
  80.         ImageTransform: Transform;  { How to get to our viewing point. }
  81.         RotationTransform: Transform;  { How far we have rotated it.      }
  82.         TotalTransform: Transform;  { Composition of the above.        }
  83.  
  84.         ourBitMaps: array[1..kNumViews] of GrafPtr; { Storage for the frames }
  85.  
  86.         systemGrafPtr: GrafPtr; { Where is TML pascal's window? }
  87.         limits: Rect;       { Boundrys of the window, more or less }
  88.  
  89.         Fifth: Real;  { Fractions of a complete circle }
  90.         Tenth: Real;
  91.  
  92.         Axis_X: Real; { Axis of rotation that we should rotate around. }
  93.         Axis_Y: Real;
  94.         Axis_Z: Real;
  95.  
  96.         icoWindow: WindowPtr;
  97.         icoArea: Rect;
  98.         ticks: longint;
  99.  
  100. { ******************************************************************** }
  101.  
  102. { Identity rotation matrix }
  103.  
  104.     procedure IdentTransform (var Atransform: Transform);
  105.         var
  106.             Row, Column: Integer;
  107.     begin
  108.         for Row := 1 to 3 do
  109.             for Column := 1 to 3 do
  110.                 Atransform[Row, Column] := 0.0;
  111.         for Row := 1 to 3 do
  112.             Atransform[Row, Row] := 1.0
  113.     end;
  114.  
  115.  
  116. { ******************************************************************** }
  117.  
  118. { Form rotation matrices }
  119.  
  120. { Rotation matrices for rotation around }
  121. {    X                 Y                  Z }
  122.  
  123. {   1   0   0        C   0   S        C   S   0   }
  124. {   0   C   S        0   1   0       -S   C   0   }
  125. {   0  -S   C       -S   0   C        0   0   1   }
  126.  
  127. { Where C= COS (Angle)   and   S= SIN (angle) }
  128.  
  129. { Around 1 means around X, 2 means around Y, and 3 means around Z}
  130.  
  131.  
  132.     procedure FormRot (Angle: Real; Around: Integer; var Result: Transform);
  133.         var
  134.             S, C: Real;
  135.             Left, Right: Integer; { The lower and upper row and column to fill }
  136.     begin
  137.         IdentTransform(Result);
  138.         S := SIN(Angle);
  139.         C := COS(Angle);
  140.         case Around of
  141.             1: 
  142.                 begin
  143.                     Left := 2;
  144.                     Right := 3
  145.                 end;
  146.             2: 
  147.                 begin
  148.                     Left := 1;
  149.                     Right := 3
  150.                 end;
  151.             3: 
  152.                 begin
  153.                     Left := 1;
  154.                     Right := 2
  155.                 end;
  156.         end;
  157.         Result[Left, Left] := C;
  158.         Result[Left, Right] := S;
  159.         Result[Right, Left] := -S;
  160.         Result[Right, Right] := C;
  161.     end;
  162.  
  163. { ******************************************************************** }
  164.  
  165.  
  166. { Multiply two transformation matricies together forming a third }
  167.  
  168.     procedure TTransform (First, Second: Transform; var Result: Transform);
  169.         var
  170.             Row, Column: integer;
  171.     begin
  172.         for Row := 1 to 3 do
  173.             for Column := 1 to 3 do
  174.                 Result[Row, Column] := First[Row, 1] * Second[1, Column] + First[Row, 2] * Second[2, Column] + First[Row, 3] * Second[3, Column]
  175.     end;
  176.  
  177.  
  178.  
  179. { ******************************************************************** }
  180.  
  181. { Add the effect of doing a given rotation onto a transformation matrix }
  182.  
  183.     procedure AddRot (Angle: Real; Around: Integer; var Result: Transform);
  184.         var
  185.             Temp, Final: Transform;
  186.     begin
  187.         FormRot(Angle, Around, Temp);
  188.         TTransform(Result, Temp, Final);
  189.         Result := Final
  190.     end;
  191. { ******************************************************************** }
  192.  
  193.  
  194. { Transform a point by the Total transformation matrix. }
  195.  
  196.     procedure TPoint (What: Coordinates; var Into: Coordinates);
  197.         var
  198.             Dimension: Integer;
  199.     begin
  200.         for Dimension := 1 to 3 do
  201.             Into[Dimension] := What[1] * TotalTransform[1, Dimension] + What[2] * TotalTransform[2, Dimension] + What[3] * TotalTransform[3, Dimension]
  202.     end;
  203.  
  204. { ******************************************************************** }
  205.  
  206. { Assuming the point given discribes a vector from the origin, produce }
  207. { a point that discribes a unit length vector from the origin.}
  208.  
  209.     procedure Normalize (var ThePoint: Coordinates);
  210.         var
  211.             Length: Real;
  212.     begin
  213.         Length := SQRT(ThePoint[1] * ThePoint[1] + ThePoint[2] * ThePoint[2] + ThePoint[3] * ThePoint[3]);
  214.         ThePoint[1] := ThePoint[1] / Length;
  215.         ThePoint[2] := ThePoint[2] / Length;
  216.         ThePoint[3] := ThePoint[3] / Length
  217.     end;
  218.  
  219.  
  220. { ******************************************************************** }
  221.  
  222.     procedure INITIALIZE;
  223.  
  224.         var
  225.             edges_So_Far: Integer;
  226.  
  227.         procedure INITPOINTS; { Where are the coordinates of an icosahedron? }
  228. { (Icosahedron with unit edges, with center at the origin) }
  229.         begin
  230.             with Vertices[1] do
  231.                 begin
  232.                     Where[1] := 0.00000000;
  233.                     Where[3] := 0.00000000;
  234.                     Where[2] := -0.95105650
  235.                 end;
  236.             with Vertices[2] do
  237.                 begin
  238.                     Where[1] := 0.00000000;
  239.                     Where[3] := 0.85065080;
  240.                     Where[2] := -0.42532537
  241.                 end;
  242.             with Vertices[3] do
  243.                 begin
  244.                     Where[1] := 0.80901699;
  245.                     Where[3] := 0.26286555;
  246.                     Where[2] := -0.42532537
  247.                 end;
  248.             with Vertices[4] do
  249.                 begin
  250.                     Where[1] := 0.49999999;
  251.                     Where[3] := -0.68819096;
  252.                     Where[2] := -0.42532537
  253.                 end;
  254.             with Vertices[5] do
  255.                 begin
  256.                     Where[1] := -0.50000001;
  257.                     Where[3] := -0.68819094;
  258.                     Where[2] := -0.42532537
  259.                 end;
  260.             with Vertices[6] do
  261.                 begin
  262.                     Where[1] := -0.80901698;
  263.                     Where[3] := 0.26286557;
  264.                     Where[2] := -0.42532537
  265.                 end;
  266.             with Vertices[7] do
  267.                 begin
  268.                     Where[1] := 0.49999999;
  269.                     Where[3] := 0.68819095;
  270.                     Where[2] := 0.42532537
  271.                 end;
  272.             with Vertices[8] do
  273.                 begin
  274.                     Where[1] := 0.80901699;
  275.                     Where[3] := -0.26286556;
  276.                     Where[2] := 0.42532537
  277.                 end;
  278.             with Vertices[9] do
  279.                 begin
  280.                     Where[1] := 0.00000000;
  281.                     Where[3] := -0.85065080;
  282.                     Where[2] := 0.42532537
  283.                 end;
  284.             with Vertices[10] do
  285.                 begin
  286.                     Where[1] := -0.80901699;
  287.                     Where[3] := -0.26286555;
  288.                     Where[2] := 0.42532537
  289.                 end;
  290.             with Vertices[11] do
  291.                 begin
  292.                     Where[1] := -0.50000001;
  293.                     Where[3] := 0.68819094;
  294.                     Where[2] := 0.42532537
  295.                 end;
  296.             with Vertices[12] do
  297.                 begin
  298.                     Where[1] := 0.00000000;
  299.                     Where[3] := 0.00000000;
  300.                     Where[2] := 0.95105650
  301.                 end
  302.         end;
  303.  
  304.  
  305.  
  306.         procedure INITfaces; { How are those vertices connected? }
  307.         begin
  308.             with faces[1] do
  309.                 begin
  310.                     Bvert[1] := 1;
  311.                     Bvert[2] := 3;
  312.                     Bvert[3] := 2
  313.                 end;
  314.             with faces[2] do
  315.                 begin
  316.                     Bvert[1] := 1;
  317.                     Bvert[2] := 4;
  318.                     Bvert[3] := 3
  319.                 end;
  320.             with faces[3] do
  321.                 begin
  322.                     Bvert[1] := 1;
  323.                     Bvert[2] := 5;
  324.                     Bvert[3] := 4
  325.                 end;
  326.             with faces[4] do
  327.                 begin
  328.                     Bvert[1] := 1;
  329.                     Bvert[2] := 6;
  330.                     Bvert[3] := 5
  331.                 end;
  332.             with faces[5] do
  333.                 begin
  334.                     Bvert[1] := 1;
  335.                     Bvert[2] := 2;
  336.                     Bvert[3] := 6
  337.                 end;
  338.             with faces[6] do
  339.                 begin
  340.                     Bvert[1] := 2;
  341.                     Bvert[2] := 7;
  342.                     Bvert[3] := 11
  343.                 end;
  344.             with faces[7] do
  345.                 begin
  346.                     Bvert[1] := 2;
  347.                     Bvert[2] := 3;
  348.                     Bvert[3] := 7
  349.                 end;
  350.             with faces[8] do
  351.                 begin
  352.                     Bvert[1] := 3;
  353.                     Bvert[2] := 8;
  354.                     Bvert[3] := 7
  355.                 end;
  356.             with faces[9] do
  357.                 begin
  358.                     Bvert[1] := 3;
  359.                     Bvert[2] := 4;
  360.                     Bvert[3] := 8
  361.                 end;
  362.             with faces[10] do
  363.                 begin
  364.                     Bvert[1] := 4;
  365.                     Bvert[2] := 9;
  366.                     Bvert[3] := 8
  367.                 end;
  368.             with faces[11] do
  369.                 begin
  370.                     Bvert[1] := 4;
  371.                     Bvert[2] := 5;
  372.                     Bvert[3] := 9
  373.                 end;
  374.             with faces[12] do
  375.                 begin
  376.                     Bvert[1] := 5;
  377.                     Bvert[2] := 10;
  378.                     Bvert[3] := 9
  379.                 end;
  380.             with faces[13] do
  381.                 begin
  382.                     Bvert[1] := 5;
  383.                     Bvert[2] := 6;
  384.                     Bvert[3] := 10
  385.                 end;
  386.             with faces[14] do
  387.                 begin
  388.                     Bvert[1] := 6;
  389.                     Bvert[2] := 11;
  390.                     Bvert[3] := 10
  391.                 end;
  392.             with faces[15] do
  393.                 begin
  394.                     Bvert[1] := 6;
  395.                     Bvert[2] := 2;
  396.                     Bvert[3] := 11
  397.                 end;
  398.             with faces[16] do
  399.                 begin
  400.                     Bvert[1] := 11;
  401.                     Bvert[2] := 7;
  402.                     Bvert[3] := 12
  403.                 end;
  404.             with faces[17] do
  405.                 begin
  406.                     Bvert[1] := 7;
  407.                     Bvert[2] := 8;
  408.                     Bvert[3] := 12
  409.                 end;
  410.             with faces[18] do
  411.                 begin
  412.                     Bvert[1] := 8;
  413.                     Bvert[2] := 9;
  414.                     Bvert[3] := 12
  415.                 end;
  416.             with faces[19] do
  417.                 begin
  418.                     Bvert[1] := 9;
  419.                     Bvert[2] := 10;
  420.                     Bvert[3] := 12
  421.                 end;
  422.             with faces[20] do
  423.                 begin
  424.                     Bvert[1] := 10;
  425.                     Bvert[2] := 11;
  426.                     Bvert[3] := 12
  427.                 end;
  428.         end;
  429.  
  430.  
  431.         procedure INITnormals;
  432. { A normal vector to a face is a vector perpendicular to the face }
  433. { In this case, defined to point outwards. }
  434.             var
  435.                 ThisFace: Integer;
  436.  
  437.       { One could compute the normal from the three edge vertices, and }
  438.     { in general this is correct.      But, since the Icosahedron is }
  439.     { defined around the origin, the normal is in the direction of   }
  440.     { the average of the directions to the vertices }
  441.             procedure FindNormal (Vertex1, Vertex2, Vertex3: Integer; var Norm: Coordinates);
  442.                 var
  443.                     index: Integer;
  444.             begin
  445.       { Find the average of the vertices }
  446.                 for index := 1 to 3 do
  447.                     Norm[index] := (Vertices[Vertex1].Where[index] + Vertices[Vertex2].Where[index] + Vertices[Vertex3].Where[index]) / 3.0;
  448.       { Make it a unit normal }
  449.                 Normalize(Norm)
  450.             end;
  451.         begin
  452. { For each face, find the surface normal }
  453.             for ThisFace := 1 to kNumFaces do
  454.                 with faces[ThisFace] do
  455.                     FindNormal(Bvert[1], Bvert[2], Bvert[3], ONormal)
  456.         end;
  457.  
  458.  
  459.  
  460.         procedure INITedges; { Given the face information, derive the edges }
  461.             var
  462.                 ThisFace: Integer;
  463.  
  464.      { IF an edge is not in the table, add it. }
  465.             function ADDedge (Vertex1, Vertex2: Integer): Integer;
  466.                 var
  467.                     First, Second: Integer;
  468.                     ThisEdge: Integer;
  469.                     Found: Boolean;
  470.             begin
  471.      { Put edge in standard order }
  472.                 if Vertex1 < Vertex2 then
  473.                     begin
  474.                         First := Vertex1;
  475.                         Second := Vertex2
  476.                     end
  477.                 else
  478.                     begin
  479.                         First := Vertex2;
  480.                         Second := Vertex1
  481.                     end;
  482.  
  483.      { Search the table for it }
  484.                 ThisEdge := 0;
  485.                 Found := False;
  486.                 repeat
  487.                     ThisEdge := ThisEdge + 1;
  488.                     if ThisEdge <= edges_so_far then
  489.                         with edges[ThisEdge] do
  490.                             Found := (First = Start) and (Second = Finish);
  491.                 until (ThisEdge >= edges_so_far) or FOUND;
  492.  
  493.      { If we don't have one, add it on. }
  494.                 if not Found then
  495.                     begin
  496.                         edges_So_far := edges_So_far + 1;
  497.                         ThisEdge := edges_So_far;
  498.                         with edges[ThisEdge] do
  499.                             begin
  500.                                 Start := First;
  501.                                 Finish := Second
  502.                             end
  503.                     end;
  504.  
  505.      { Return an index to it.}
  506.                 AddEdge := ThisEdge
  507.             end;
  508.  
  509.         begin
  510.             edges_So_Far := 0;
  511.  
  512. { For each face, add its edges to the list }
  513.             for ThisFace := 1 to kNumFaces do
  514.                 with faces[ThisFace] do
  515.                     begin
  516.                         Bedges[1] := AddEdge(Bvert[1], Bvert[2]);
  517.                         Bedges[2] := AddEdge(Bvert[2], Bvert[3]);
  518.                         Bedges[3] := AddEdge(Bvert[1], Bvert[3])
  519.                     end;
  520.         end;
  521.  
  522.  
  523.  
  524. { Come up with some shading patterns. }
  525.  
  526.         procedure InitPat;
  527.             var
  528.                 Row, Column, Entry, Sample: integer;
  529.                 Loc, Temp, Size: Integer;
  530.                 TwoToThe: array[0..7] of 0..255;
  531.             function MakeRGB (r, g, b: Integer): RGBColor;
  532.             begin
  533.                 MakeRGB.red := r;
  534.                 MakeRGB.green := g;
  535.                 MakeRGB.blue := b;
  536.             end; {MakeRGB}
  537.         begin
  538.  
  539.             if gColorQDFlag then
  540.                 begin
  541.                     for entry := 0 to 64 do
  542.                         cpatterns[entry] := MakeRGB(BSL(entry, 9), BSL(entry, 9), BSL(entry, 9));
  543.                     Exit(InitPat);
  544.                 end;
  545.  
  546. { Initialize a table of powers of 2 }
  547.             Sample := 1;
  548.             for Temp := 0 to 7 do
  549.                 begin
  550.                     TwoToThe[Temp] := Sample;
  551.                     Sample := Sample + Sample
  552.                 end;
  553.  
  554. { Start shading patterns Black }
  555.             for Entry := 0 to 64 do
  556.                 for Row := 0 to 7 do
  557.                     patterns[Entry][Row] := 0;
  558.  
  559. { Place dots in as evenly as practical }
  560. { The Macintosh has the convention that a bit =1 is black, and a }
  561. { a bit = 0 is white. }
  562.             for Entry := 63 downto 0 do
  563.                 begin
  564.                     Loc := Entry;
  565.                     Row := 0;
  566.                     Column := 0;
  567.                     Size := 8;
  568.                     for Temp := 1 to 3 do
  569.                         begin
  570.                             Row := Row + Row;
  571.                             Column := Column + Column;
  572.                             case Loc mod 4 of
  573.            { Dither matrix recursively applied: }
  574.            { 0 3 }
  575.            { 2 1 }
  576.                                 0: 
  577.                                     ;
  578.                                 1: 
  579.                                     begin
  580.                                         Row := Row + 1;
  581.                                         Column := Column + 1
  582.                                     end;
  583.                                 2: 
  584.                                     Row := Row + 1;
  585.                                 3: 
  586.                                     Column := Column + 1;
  587.                             end;
  588.                             Loc := Loc div 4
  589.                         end;
  590.                     Sample := TwoToThe[Column];
  591.                     for Temp := Entry downto 0 do
  592.                         patterns[Temp][Row] := patterns[Temp][Row] + Sample
  593.                 end
  594.         end; {InitPat}
  595.  
  596.  
  597.  
  598. { Start out with no transformations }
  599.         procedure InitTransforms;
  600.         begin
  601.             IdentTransform(TotalTransform);
  602.             IdentTransform(RotationTransform);
  603.             IdentTransform(ImageTransform);
  604.         end;
  605.  
  606. { Get memory for the frames }
  607.         procedure InitFrames;
  608.             var
  609.                 index: Integer;
  610.         begin
  611. { Obtain and Initialize frame records }
  612.             for index := 1 to kNumViews do
  613.                 OTNewGWorld(ourBitMaps[index], limits);
  614.         end; {InitFrames}
  615.  
  616. { What axis should this thing seem to rotate around? }
  617.         procedure InitAxis;
  618.         begin
  619. { The direction }
  620.             Axis_X := -Tenth;
  621.             Axis_Y := 0.0;
  622.             Axis_Z := Tenth;
  623.  
  624. { Matrix to get us there }
  625.             FormRot(Axis_X, 1, ImageTransform);
  626.             AddRot(Axis_Y, 2, ImageTransform);
  627.             AddRot(Axis_Z, 3, ImageTransform);
  628.         end;
  629.  
  630.         procedure InitLight; { Set up the light source }
  631. { Shading is going to be Cosine shading.  Brightness is proportional to }
  632. { the cosine of the angle between Bright vector and the Eye.  Bright    }
  633. { Vector is the direction of the bright spot on the object, which is    }
  634. { Half way between the Eye and the light. }
  635.  
  636.             var
  637.                 Eye: Coordinates; { Direction to the Eye }
  638.         begin
  639.  
  640. { Intended direction of light}
  641.             light[1] := 3.0;
  642.             light[2] := -1.0;
  643.             light[3] := 1.0;
  644.             Normalize(light); { Unit directions only. }
  645.  
  646. { Direction of Eye. Forced by physical model, Don't Change this. }
  647.             Eye[1] := 0.0;
  648.             Eye[2] := 0.0;
  649.             Eye[3] := 1.0;
  650.             Normalize(Eye);
  651.  
  652. { Average of unit vector to the eye and the light }
  653.             light[1] := (light[1] + Eye[1]) / 2.0;
  654.             light[2] := (light[2] + Eye[2]) / 2.0;
  655.             light[3] := (light[3] + Eye[3]) / 2.0;
  656.             Normalize(light)      { Make it a unit direction}
  657.         end;
  658.  
  659.  
  660.  
  661.  
  662.     begin { Get everything we need }
  663.         Fifth := (2 * PI) / 5.0;
  664.         Tenth := PI / 5.0;
  665.         GetPort(systemGrafPtr);
  666. {systemBitMap := systemGrafPtr^.PortBits;}
  667.         SetRect(limits, 0, 0, kFullHeight, kFullHeight);
  668.         INITPOINTS;
  669.         INITfaces;
  670.         InitNormals;
  671.         INITedges;
  672.         InitPat;
  673.         InitTransforms;
  674.         InitFrames;
  675.         InitAxis;
  676.         InitLight
  677.     end;
  678.  
  679.  
  680. { ******************************************************************** }
  681.  
  682. { Find the visible faces and edges }
  683.  
  684.     procedure FindVisible;
  685.         var
  686.             ThisFace: Integer;
  687.             ThisEdge: Integer;
  688.     begin
  689.         for ThisEdge := 1 to kNumEdges do
  690.             with edges[ThisEdge] do
  691.                 Visible := False;
  692.  
  693. { For each face, if the face is visible, mark it and it's edges visible }
  694.         for ThisFace := 1 to kNumFaces do
  695.             with faces[ThisFace] do
  696.                 begin
  697.    { Assuming that we have a CONVEX object, then the face pointing towards }
  698.    { us means that it MUST be visible }
  699.                     Shows := Normal[3] >= 0.0;
  700.                     if Shows then
  701.                         begin
  702.                             edges[Bedges[1]].Visible := true;
  703.                             edges[Bedges[2]].Visible := true;
  704.                             edges[Bedges[3]].Visible := true
  705.                         end
  706.                 end
  707.     end;
  708.  
  709. { ******************************************************************** }
  710.  
  711. { Compute Display Coordinates for each point}
  712. { (with the current transformation) }
  713.  
  714.     procedure SetDisplay;
  715.         var
  716.             ThisPoint: Integer;
  717.     begin
  718. { We assume that the Object is defined centered around the origin. }
  719.         for ThisPoint := 1 to kNumVertices do
  720.             with Vertices[ThisPoint] do
  721.                 begin
  722.                     DX := ROUND((NowAt[1] + 1.0) * kHalfHeight);
  723.                     DY := ROUND((NowAt[2] + 1.0) * kHalfHeight)
  724.                 end;
  725.     end;
  726.  
  727. { ******************************************************************** }
  728.  
  729. { Glue code for drawing shades }
  730.  
  731.     procedure MyFillRgn (aRegion: RgnHandle; level: Integer);
  732.     begin
  733.         if aRegion = nil then
  734.             Exit(MyFillRgn);
  735.         if gColorQDFlag then
  736.             begin
  737.                 RGBForeColor(cpatterns[level]);
  738.                 PaintRgn(aRegion);
  739.                 ForeColor(blackColor);
  740.             end
  741.         else
  742.             FillRgn(aRegion, patterns[level]);
  743.     end; {MyFillRgn}
  744.  
  745.     procedure MyFillRect (aRect: Rect; level: Integer);
  746.     begin
  747.         if gColorQDFlag then
  748.             begin
  749.                 RGBForeColor(cpatterns[level]);
  750.                 PaintRect(aRect);
  751.                 ForeColor(blackColor);
  752.             end
  753.         else
  754.             FillRect(aRect, patterns[level]);
  755.     end; {MyFillRect}
  756.  
  757.     procedure MyBackPat (level: Integer);
  758.     begin
  759.         if gColorQDFlag then
  760.             RGBBackColor(cpatterns[level])
  761.         else
  762.             BackPat(patterns[level]);
  763.     end; {MyBackPat}
  764.  
  765.     procedure MyPenPat (level: Integer);
  766.     begin
  767.         if gColorQDFlag then
  768.             RGBForeColor(cpatterns[level])
  769.         else
  770.             PenPat(patterns[level]);
  771.     end; {MyPenPat}
  772.  
  773. { ******************************************************************** }
  774.  
  775. { Display the visible edges }
  776.  
  777.     procedure Drawedges;
  778.         var
  779.             ThisEdge: Integer;
  780.     begin
  781.         SetDisplay;
  782.         for ThisEdge := 1 to kNumEdges do
  783.             with edges[ThisEdge] do
  784.                 if Visible then
  785.                     begin
  786.                         with Vertices[Start] do
  787.                             MoveTo(DX, DY);
  788.                         with Vertices[Finish] do
  789.                             LineTo(DX, DY)
  790.                     end
  791.     end;
  792.  
  793. { ******************************************************************** }
  794.  
  795. { Compute the brightnesses of the faces. }
  796.  
  797.     procedure Shadefaces;
  798.         var
  799.             ThisFace: Integer;
  800.             aRegion: RgnHandle;
  801.             Level: Integer;
  802.  
  803.         function Bright (PlaneNorm, LightNorm: Coordinates): Real;
  804.         begin
  805.     { Brightness should be proportional to the cosine of the angle }
  806.     { between the face normal and the Bright spot.  The dot        }
  807.     { product of the Normal and the Bright spot vectors would give }
  808.     { Cosine angle * Length Bright * Length Face Normal,           }
  809.     { But since we have arranged for both lengths to be 1, this    }
  810.     { gives just Cosine Angle which is what we want.               }
  811.             Bright := ((PlaneNorm[1] * LightNorm[1] + PlaneNorm[2] * LightNorm[2] + PlaneNorm[3] * LightNorm[3]) + 1.0) / 2.0
  812.     { We scale the value to lie between 0 (Black) and 1 (White)    }
  813.         end;
  814.     begin
  815.         aRegion := NewRgn;
  816. { For each visible face... }
  817.         for ThisFace := 1 to kNumFaces do
  818.             with faces[ThisFace] do
  819.                 if Shows then
  820.                     begin
  821.  
  822.     { Form the region for the face for the MacIntosh primitives }
  823.                         OpenRgn;
  824.                         with Vertices[Bvert[3]] do
  825.                             MoveTo(DX, DY);
  826.                         with Vertices[Bvert[1]] do
  827.                             LineTo(DX, DY);
  828.                         with Vertices[Bvert[2]] do
  829.                             LineTo(DX, DY);
  830.                         with Vertices[Bvert[3]] do
  831.                             Lineto(DX, DY);
  832.                         CloseRgn(aRegion);
  833.  
  834.     { Fill with the computed brightness }
  835.                         level := Round(Bright(Normal, light) * 64.0);
  836.                         MyFillRgn(aRegion, level);
  837.                         SetEmptyRgn(aRegion)
  838.                     end;
  839.         DisposeRgn(aRegion)
  840.     end; {Shadefaces}
  841.  
  842. { ******************************************************************** }
  843.  
  844.  
  845. { Transform the faces and vertices by the current transformation }
  846.  
  847.     procedure DoTransform;
  848.         var
  849.             ThisFace, ThisPoint: Integer;
  850.     begin
  851.         for ThisFace := 1 to kNumFaces do
  852.             with faces[ThisFace] do
  853.                 TPoint(ONormal, Normal);
  854.         for ThisPoint := 1 to kNumVertices do
  855.             with Vertices[ThisPoint] do
  856.                 Tpoint(Where, NowAt)
  857.     end;
  858.  
  859. { ******************************************************************** }
  860.  
  861. { Build the current transformation from its parts, apply the transform, }
  862. { and compute the visible faces and edges. }
  863.  
  864.     procedure SetupFrame;
  865.     begin
  866.         TTransform(RotationTransform, ImageTransform, TotalTransform);
  867.         DoTransform;
  868.         SetDisplay;
  869.         FindVisible
  870.     end;
  871.  
  872. { ******************************************************************** }
  873.  
  874. { Draw one frame }
  875.     procedure OutFrame;
  876.     begin
  877.         SetupFrame;
  878.         MyFillRect(limits, 0);
  879.         Shadefaces;
  880.         Drawedges
  881.     end;
  882.  
  883. { ******************************************************************** }
  884.  
  885. { Draw the frames of the Object in each orientation. }
  886.  
  887.     procedure ComputeFrames;
  888.         var
  889.             index: Integer;
  890.             This_Angle, Step_Angle: Real;
  891.             savePort: GrafPtr;
  892.             saveDev: GDHandle;
  893.     begin
  894.         Step_Angle := Fifth / kNumViews; { Assume 5 fold rotational symetry }
  895.         OTGetGWorld(savePort, saveDev); {This should be the screen!}
  896. {Let's make sure the window's colors are CopyBits-friendly!}
  897.         ForeColor(blackColor);
  898.         BackColor(whiteColor);
  899.         for index := 1 to kNumViews do
  900.             begin
  901.                 This_Angle := index * Step_Angle;
  902.                 FormRot(This_Angle, 2, RotationTransform);
  903.                 OTSetGWorld(ourBitMaps[index], nil);
  904. {SetPortBits(ourBitMaps[index]);}
  905.                 OutFrame;
  906.                 OTSetGWorld(savePort, saveDev);
  907.                 CopyBits(ourBitMaps[index]^.portBits, systemGrafPtr^.PortBits, limits, limits, srcCopy, nil); {systemGrafPtr^.visRgn}
  908.             end;
  909.         OTSetGWorld(savePort, saveDev);
  910. {SetPortBits(systemGrafPtr^.PortBits)}
  911.     end; {ComputeFrames}
  912.  
  913.  
  914. { ******************************************************************** }
  915.  
  916. { Thumb through the frames, copying each to the screen.  Change the }
  917. { Aiming point (and thumb direction ) to mimic bouncing }
  918.  
  919.     procedure Thumb;
  920.         var
  921.             index: Integer;
  922.             dest: Rect;
  923.             offset_X, direction_X: Integer;
  924.             offset_Y, direction_Y: Integer;
  925.             direction_Rot: Integer;
  926.             bounce: Rect;
  927.             startTicks: Longint;
  928.     begin
  929.         ForeColor(blackColor);
  930.         BackColor(whiteColor);
  931.  
  932.         index := 0;
  933.         direction_Rot := 1;
  934.         offset_X := 0;
  935.         direction_X := 1;
  936.         offset_Y := 0;
  937.         direction_Y := 1;
  938.         SetOrigin(0, 0);
  939.  
  940.         bounce := systemGrafPtr^.portRect;
  941.         bounce.right := bounce.right - kFullHeight;
  942.         bounce.bottom := bounce.bottom - kFullHeight;
  943.         dest := limits;
  944.  
  945.         while not Button do
  946.             begin
  947.                 startTicks := TickCount;
  948.  
  949. { Select frame, Force wrap if off ends of frame list. }
  950.                 index := index + direction_Rot;
  951.                 if index > kNumViews then
  952.                     index := 1
  953.                 else if index < 1 then
  954.                     index := kNumViews;
  955.  
  956. { Copy this frame to screen }
  957.                 CopyBits(ourBitMaps[index]^.portBits, systemGrafPtr^.portBits, limits, dest, srcCopy, nil); {systemGrafPtr^.visRgn}
  958.  
  959. { Update X, check for bounce }
  960.                 offset_X := offset_X + direction_X;
  961.                 if (offset_X > bounce.Right) or (offset_X < bounce.Left) then
  962.                     begin
  963.                         direction_X := -direction_X;
  964.                         direction_Rot := direction_X * direction_Y;
  965.                     end;
  966.  
  967. { Update Y, check for bounce }
  968.                 offset_Y := offset_Y + direction_Y;
  969.                 if (offset_Y > bounce.Bottom) or (offset_Y < bounce.Top) then
  970.                     begin
  971.                         direction_Rot := direction_X * direction_Y;
  972.                         direction_Y := -direction_Y;
  973.                     end;
  974.  
  975. { Update current location for transfer. }
  976.                 dest := limits;
  977.                 OffsetRect(dest, offset_X, offset_Y);
  978.  
  979.                 while startTicks + 1 > TickCount do
  980.                     ;
  981.             end;
  982.  
  983.         while Button do { Nothing }
  984.             ;
  985.     end; {Thumb}
  986.  
  987.     procedure Get_New_Window;
  988.     begin
  989.         if gColorQDFlag then
  990.             icoWindow := GetNewCWindow(128, nil, WindowPtr(-1))
  991.         else
  992.             icoWindow := GetNewWindow(128, nil, WindowPtr(-1));
  993.         ShowWindow(icoWindow);
  994.         SetPort(icoWindow);
  995.  
  996.         SetRect(icoArea, 0, 0, 475, 275);
  997.     end; {Get_New_Window}
  998.  
  999. {Draw a string centered in the port}
  1000.  
  1001.     procedure CenterString (s: Str255; height: Integer);
  1002.     begin
  1003.         MoveTo((thePort^.portRect.right - thePort^.portRect.left - StringWidth(s)) div 2, height);
  1004.         DrawString(s);
  1005.     end; {CenterString}
  1006.  
  1007. { ******************************************************************** }
  1008.  
  1009.  
  1010. begin
  1011. {$IFC UNDEFINED THINK_PASCAL}
  1012.     InitGraf(@qd.thePort);
  1013.     InitFonts;
  1014.     InitWindows;
  1015.     InitMenus;
  1016.     TEInit;
  1017.     InitDialogs(nil);
  1018.     MaxApplZone;
  1019. {$ENDC}
  1020.  
  1021.     OTInitGlobals;
  1022.  
  1023.     Get_New_Window;
  1024.     HideCursor;
  1025.     CenterString('Icosahedron Version 0.6', 20);
  1026.     CenterString('(c) Copyright 1986 By the University of Utah Computer Center', 40);
  1027.     CenterString('Written by John Halleck  (NSS 20620)', 60);
  1028.     Delay(90, ticks);
  1029.     TextFace([bold]);
  1030.     CenterString('Brought back to life at itty bitty bytes™,', 90);
  1031.     CenterString(' 25 September 1994,', 110);
  1032.     CenterString('by Kenneth A. Long', 130);
  1033.     Delay(120, ticks);
  1034.     TextFace([bold]);
  1035.     ForeColor(redColor);
  1036.     CenterString('Even some more life (color, palettes) put into it,', 170);
  1037.     ForeColor(magentaColor);
  1038.     CenterString('plus some much needed delays,', 190);
  1039.     ForeColor(blueColor);
  1040.     CenterString('October 1995,', 210);
  1041.     ForeColor(greenColor);
  1042.     CenterString('by Ingemar R', 230);
  1043.     Delay(120, ticks);
  1044.     INITIALIZE;
  1045. {SetPort(systemGrafPtr);}
  1046.     for index := 64 downto 0 do
  1047.         begin
  1048.             MyFillRect(systemGrafPtr^.portRect, index);
  1049.             Delay(1, ticks);
  1050.         end;
  1051.     MyBackPat(0);
  1052.     SetupFrame;
  1053.     MyPenPat(64);
  1054.     Drawedges;
  1055.     MyPenPat(0);
  1056.     Shadefaces;
  1057.     Drawedges;
  1058.     ComputeFrames;
  1059.     Thumb;
  1060.     if gColorQDFlag then
  1061.         RestoreDeviceClut(nil);
  1062.     ShowCursor;
  1063.     FlushEvents(mDownMask, 0);
  1064. end.